package com.fingard.dsp.bank.directbank.cmb06.util;

import org.bouncycastle.util.encoders.Base64;

import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;


/**
 * @author: ggp
 * @Date: 2019/11/6 15:27
 * @Description: 签名验签工具类  provider是BC
 */
public class SignatureUtil {
    /**
     * 签名
     *
     * @param signatureAlgorithmName 签名算法名字
     * @param key                    私钥
     * @param source                 签名原文
     * @return Base64字符串
     */
    public static String signature(String signatureAlgorithmName, PrivateKey key, String source) throws Exception {
        if(!SignatureAlgorithmEnum.contain(signatureAlgorithmName)){
            throw new Exception("不支持的签名算法");
        }
        try {
            Signature signature = Signature.getInstance(signatureAlgorithmName);
            signature.initSign(key);
            signature.update(source.getBytes());
            byte[] out = signature.sign();
            return new String(Base64.encode(out));
        } catch (Exception e) {
            throw new Exception("签名失败", e);
        }
    }

    /**
     * 验签
     *
     * @param signatureAlgorithmName 签名算法名字
     * @param key                    公钥
     * @param source                 签名原文
     * @param sign                   签名值
     * @return
     */
    public static boolean verify(String signatureAlgorithmName, PublicKey key, String source, String sign) throws Exception {
        if(!SignatureAlgorithmEnum.contain(signatureAlgorithmName)){
            throw new Exception("不支持的签名算法");
        }
        try {
            Signature signature = Signature.getInstance(signatureAlgorithmName);
            signature.initVerify(key);
            signature.update(source.getBytes());
            return signature.verify(Base64.decode(sign.getBytes()));
        } catch (Exception e) {
            throw new Exception("验签失败", e);
        }
    }
    /**
     * 签名 签名算法为SM3WithSM2
     *
     * @param key    私钥
     * @param source 签名原文
     * @return
     */
    public static String signatureBySm3WithSm2(PrivateKey key, String source) throws Exception {
        return signature(SignatureAlgorithmEnum.SM3_WITH_SM2.name, key, source);
    }

    /**
     * 验签 签名算法为SM3WithSM2
     *
     * @param key    公钥
     * @param source 签名原文
     * @param sign   签名值
     * @return
     */
    public static boolean verifyBySm3WithSm2(PublicKey key, String source, String sign) throws Exception {
        return verify(SignatureAlgorithmEnum.SM3_WITH_SM2.name, key, source, sign);
    }

    /**
     * 签名 签名算法为SH1WithRSA
     * @param key    私钥
     * @param source 签名原文
     * @return
     * @throws Exception
     */
    public static String signatureBySHA1WithRSA(PrivateKey key,String source) throws  Exception{
        return signature(SignatureAlgorithmEnum.SHA1_WITH_RSA.name,key,source);
    }

    /**
     * 验签 签名算法为SHA1WithRSA
     * @param key    公钥
     * @param source 签名原文
     * @param sign   签名值
     * @return
     * @throws Exception
     */
    public static boolean verifyBySHA1WithRSA(PublicKey key,String source,String sign) throws Exception{
        return verify(SignatureAlgorithmEnum.SHA1_WITH_RSA.name,key,source,sign);
    }

    /**
     * 签名 签名算法为SHA256WithRSA
     * @param key    私钥
     * @param source 签名原文
     * @return
     * @throws Exception
     */
    public static String signatureBySHA256WithRSA(PrivateKey key,String source) throws Exception{
        return signature(SignatureAlgorithmEnum.SHA256_WITH_RSA.name,key,source);
    }

    /**
     * 验签 签名算法为SHA256WithRSA
     * @param key    公钥
     * @param source 签名原文
     * @param sign   签名值
     * @return
     * @throws Exception
     */
    public static boolean verifyBySHA256WithRSA(PublicKey key,String source,String sign) throws Exception{
        return verify(SignatureAlgorithmEnum.SHA256_WITH_RSA.name,key,source,sign);
    }
}
enum SignatureAlgorithmEnum {
    SM3_WITH_SM2("1.2.156.10197.1.501", "SM3WithSM2"),
    SHA1_WITH_RSA("1.2.840.113549.1.1.5", "SHA1WithRSA"),
    SHA256_WITH_RSA("1.2.840.113549.1.1.11", "SHA256WithRSA"),
    SHA256_WITH_ECDSA("1.2.840.10045.4.3.2","SHA256WithECDSA");
    public String oid;
    public String name;

    SignatureAlgorithmEnum(String oid, String name) {
        this.oid = oid;
        this.name = name;
    }

    /**
     * 判断是否支持该签名算法
     * @param name
     * @return
     */
    public static boolean contain(String name){
        for(SignatureAlgorithmEnum signatureAlgorithmEnum:SignatureAlgorithmEnum.values()){
            if(signatureAlgorithmEnum.name.equals(name)){
                return true;
            }
        }
        return false;
    }
}
